<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community</title>
    <description>The most recent home feed on DEV Community.</description>
    <link>https://dev.to</link>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed"/>
    <language>en</language>
    <item>
      <title>I Built an AI That Fixes Terraform Drift Automatically</title>
      <dc:creator>Sudarshan Thakur</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:37:22 +0000</pubDate>
      <link>https://dev.to/sudarshan_thakur_1e141b99/i-built-an-ai-that-fixes-terraform-drift-automatically-p97</link>
      <guid>https://dev.to/sudarshan_thakur_1e141b99/i-built-an-ai-that-fixes-terraform-drift-automatically-p97</guid>
      <description>&lt;p&gt;I Built an AI That Fixes Terraform Drift Automatically&lt;/p&gt;

&lt;p&gt;If you've worked with Terraform long enough, you know the feeling. You run terraform plan and suddenly there are 12 unexpected changes. Someone tweaked an instance type in the console. A security group rule got added manually. A tag got removed. Your infrastructure drifted — and now you have to figure out what changed, why, and how to bring it back in line.&lt;/p&gt;

&lt;p&gt;Detecting drift is one thing. Actually fixing it is where engineers waste hours.&lt;/p&gt;

&lt;p&gt;That's what I built tfdrift remediate to solve.&lt;/p&gt;

&lt;p&gt;What is tfdrift?&lt;/p&gt;

&lt;p&gt;tfdrift (&lt;a href="https://github.com/sudarshan8417/tfdrift" rel="noopener noreferrer"&gt;https://github.com/sudarshan8417/tfdrift&lt;/a&gt;) is an open-source CLI for continuous Terraform and OpenTofu drift detection. It runs terraform plan across all your workspaces, classifies drift by severity (critical/high/medium/low), and sends alerts to Slack, Teams, or OpsGenie.&lt;/p&gt;

&lt;p&gt;Version 0.5.3 ships a new command — tfdrift remediate — that takes detected drift and uses AI to generate a ready-to-review .tf remediation file.&lt;/p&gt;

&lt;p&gt;The Problem With Fixing Drift Manually&lt;/p&gt;

&lt;p&gt;When drift is detected, the typical workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Look at the terraform plan output&lt;/li&gt;
&lt;li&gt;Figure out which attributes changed&lt;/li&gt;
&lt;li&gt;Manually update your .tf files to match desired state&lt;/li&gt;
&lt;li&gt;Run terraform apply&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For 1-2 resources this is fine. For 10+ resources across multiple workspaces, it becomes a slow, error-prone process — especially when you're dealing with complex resource types like aws_security_group, aws_iam_role_policy, or azurerm_virtual_network.&lt;/p&gt;

&lt;p&gt;How tfdrift remediate Works&lt;/p&gt;

&lt;p&gt;The flow is simple:&lt;/p&gt;

&lt;p&gt;tfdrift remediate --path ./infra&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scans all your Terraform workspaces for drift&lt;/li&gt;
&lt;li&gt;Lists every drifted resource with severity and number of changed attributes&lt;/li&gt;
&lt;li&gt;Asks whether you want to fix everything or just specific resources&lt;/li&gt;
&lt;li&gt;Calls AI (Claude or GPT-4o) with full drift context&lt;/li&gt;
&lt;li&gt;Writes a drift-remediation.tf file you can review and apply&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's what the interactive prompt looks like:&lt;/p&gt;

&lt;p&gt;Found 3 drifted resource(s):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;aws_instance.web  🔴 high — 2 attribute change(s)&lt;/li&gt;
&lt;li&gt;aws_s3_bucket.logs  🟡 medium — 1 attribute change(s)&lt;/li&gt;
&lt;li&gt;aws_security_group.app  🔴 high — 3 attribute change(s)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What would you like to remediate?&lt;br&gt;
  A — All resources&lt;br&gt;
  S — Select specific resources (comma-separated numbers)&lt;br&gt;
  Q — Quit&lt;/p&gt;

&lt;p&gt;Choice [A]:&lt;/p&gt;

&lt;p&gt;Choose S and enter 1,3 to fix only the high-severity ones. Or hit A to generate remediation for everything.&lt;/p&gt;

&lt;p&gt;The AI Output&lt;/p&gt;

&lt;p&gt;The AI receives the full drift context — resource type, action needed, and every attribute that changed with its desired vs actual value. It outputs valid HCL with inline comments explaining each correction:&lt;/p&gt;

&lt;h1&gt;
  
  
  drift-remediation.tf
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Generated by tfdrift remediate
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Drift detected: 3 resource(s) across 1 workspace(s)
&lt;/h1&gt;

&lt;h1&gt;
  
  
  aws_instance.web — instance_type drifted from t3.medium to t3.large
&lt;/h1&gt;

&lt;h1&gt;
  
  
  aws_security_group.app — ingress rules modified out-of-band
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Restores instance type to desired state (was changed from t3.medium to t3.large in console)
&lt;/h1&gt;

&lt;p&gt;resource "aws_instance" "web" {&lt;br&gt;
  instance_type = "t3.medium"  # corrected: actual was t3.large&lt;br&gt;
  # ... other attributes unchanged&lt;br&gt;
}&lt;/p&gt;

&lt;h1&gt;
  
  
  Removes manually added ingress rules
&lt;/h1&gt;

&lt;p&gt;resource "aws_security_group" "app" {&lt;br&gt;
  ingress {&lt;br&gt;
    from_port   = 443&lt;br&gt;
    to_port     = 443&lt;br&gt;
    protocol    = "tcp"&lt;br&gt;
    cidr_blocks = ["10.0.0.0/8"]&lt;br&gt;
  }&lt;br&gt;
  # ... other attributes unchanged&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Review it, make any adjustments, then apply:&lt;/p&gt;

&lt;p&gt;terraform apply drift-remediation.tf&lt;/p&gt;

&lt;p&gt;Dual AI Provider Support&lt;/p&gt;

&lt;p&gt;tfdrift remediate auto-detects which AI provider to use based on your environment variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set ANTHROPIC_API_KEY → uses Claude (preferred)&lt;/li&gt;
&lt;li&gt;Set OPENAI_API_KEY → uses GPT-4o (fallback)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also force a specific provider:&lt;/p&gt;

&lt;p&gt;tfdrift remediate --provider openai --path ./infra&lt;/p&gt;

&lt;p&gt;Getting Started&lt;/p&gt;

&lt;p&gt;pip install 'tfdrift[ai]'&lt;/p&gt;

&lt;h1&gt;
  
  
  with Claude
&lt;/h1&gt;

&lt;p&gt;export ANTHROPIC_API_KEY=sk-ant-...&lt;br&gt;
tfdrift remediate --path ./infra&lt;/p&gt;

&lt;h1&gt;
  
  
  with OpenAI
&lt;/h1&gt;

&lt;p&gt;export OPENAI_API_KEY=sk-...&lt;br&gt;
tfdrift remediate --path ./infra&lt;/p&gt;

&lt;p&gt;Optional flags:&lt;/p&gt;

&lt;h1&gt;
  
  
  Fix everything without the interactive prompt
&lt;/h1&gt;

&lt;p&gt;tfdrift remediate --all&lt;/p&gt;

&lt;h1&gt;
  
  
  Custom output file
&lt;/h1&gt;

&lt;p&gt;tfdrift remediate --output my-fixes.tf&lt;/p&gt;

&lt;h1&gt;
  
  
  Use OpenTofu instead of Terraform
&lt;/h1&gt;

&lt;p&gt;tfdrift remediate --binary tofu&lt;/p&gt;

&lt;p&gt;Why Not Just Run terraform apply?&lt;/p&gt;

&lt;p&gt;tfdrift remediate is not the same as tfdrift scan --auto-fix (which actually runs terraform apply). The AI remediation command generates a file for you to review first — the AI explains what it's correcting and why, you verify it looks right, then you apply.&lt;/p&gt;

&lt;p&gt;This matters in production. You want a human reviewing the fix before it touches infrastructure.&lt;/p&gt;

&lt;p&gt;What's Next&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for multi-workspace remediation plans in a single file&lt;/li&gt;
&lt;li&gt;Severity filtering (--min-severity high to only remediate critical and high drift)&lt;/li&gt;
&lt;li&gt;GitHub PR generation — auto-open a PR with the remediation file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;tfdrift is open source (Apache 2.0). If you're using it or have feedback, open an issue or drop a star on GitHub (&lt;a href="https://github.com/sudarshan8417/tfdrift" rel="noopener noreferrer"&gt;https://github.com/sudarshan8417/tfdrift&lt;/a&gt;).&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>devops</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Styled Unicode Breaks Character Counters</title>
      <dc:creator>Eugen</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:36:52 +0000</pubDate>
      <link>https://dev.to/3ugen/styled-unicode-breaks-character-counters-fg1</link>
      <guid>https://dev.to/3ugen/styled-unicode-breaks-character-counters-fg1</guid>
      <description>&lt;p&gt;A 76-character bio, styled once, no longer has one useful length.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;𝐚𝐞𝐬𝐭𝐡𝐞𝐭𝐢𝐜&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;                          &lt;span class="c1"&gt;// 9   code points (and 9 graphemes here)&lt;/span&gt;
&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;                               &lt;span class="c1"&gt;// 18  UTF-16 units — what String.length counts&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;     &lt;span class="c1"&gt;// 36  UTF-8 bytes  — what storage counts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three defensible answers, factor of four on one word. I found this while auditing a counter beside field limits I do not own. The counter reported code points; the destination's unit was unknown. That is already enough to make a green "safe" verdict dishonest.&lt;/p&gt;

&lt;p&gt;Styled letters from the Mathematical Alphanumeric Symbols block live in the Supplementary Plane: &lt;strong&gt;1 code point = 2 UTF-16 units = 4 UTF-8 bytes&lt;/strong&gt;. If you display one number next to a limit documented only as "characters", you are making a claim about a unit the destination never published.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a real bio line does
&lt;/h2&gt;

&lt;p&gt;Same 76-code-point line, four styles. Measured, not recalled:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;style&lt;/th&gt;
&lt;th&gt;code points&lt;/th&gt;
&lt;th&gt;UTF-16&lt;/th&gt;
&lt;th&gt;UTF-8 bytes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;plain&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bold &lt;code&gt;𝐀&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;td&gt;134&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Script &lt;code&gt;𝒜&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;td&gt;117&lt;/td&gt;
&lt;td&gt;225&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Small Caps &lt;code&gt;ᴀ&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;td&gt;155&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A code-point counter calls Bold "76". The same text occupies 134 UTF-16 units or 250 UTF-8 bytes. If the destination budgets one of those units, a verdict based on another is meaningless. Documentation that says only "characters" does not resolve it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest UI: three states, not a green number
&lt;/h2&gt;

&lt;p&gt;Measure all three. If the destination explicitly publishes a byte limit, enforce it. If it publishes a character limit without naming the unit, keep bytes visible but do not compare them to the same number: byte and character budgets are not interchangeable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;measure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;codePoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;utf16&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// ok    — fits by code points and UTF-16; bytes are reported separately&lt;/span&gt;
&lt;span class="c1"&gt;// risk  — fits by code points, not by UTF-16: the field decides, and it did not say&lt;/span&gt;
&lt;span class="c1"&gt;// over  — too long even by the most generous count&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;codePoints&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;over&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utf16&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;risk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ok&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;risk&lt;/code&gt; is the honest answer when the platform has not told you the unit. The only way to name the unit is to paste a known-length styled string into the live field and see where it cuts. Until then, do not draw a green bar.&lt;/p&gt;

&lt;h2&gt;
  
  
  The next failure is truncation, not the count
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;.slice()&lt;/code&gt;, &lt;code&gt;.substring()&lt;/code&gt;, and &lt;code&gt;[0..n]&lt;/code&gt; on a JavaScript string cut at UTF-16 boundaries. An odd index inside a Supplementary character keeps half a surrogate pair. Many encoders and renderers replace that lone surrogate with U+FFFD:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;𝐚𝐞𝐬𝐭𝐡𝐞𝐭𝐢𝐜&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// "𝐚𝐞𝐬\uD835"  → renders 𝐚𝐞𝐬�&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Truncate on code points — and on grapheme clusters if you allow combining marks (&lt;code&gt;a̶&lt;/code&gt; is two code points):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cutCodePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cutGraphemes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Segmenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;granularity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;grapheme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where the rest of the measurements live
&lt;/h2&gt;

&lt;p&gt;I did not want a second guessed number in the UI, so I ran this against a shipping 22-style catalog rather than a handful of examples. Length units, the NFKC rule that flattens 17 of those 22 styles, coverage holes per family, and how &lt;code&gt;/\d/&lt;/code&gt; in JavaScript disagrees with Python on &lt;code&gt;𝟐𝟎𝟐𝟔&lt;/code&gt; are written up with the reproducing code in &lt;a href="https://fontius.app/skills/unicode-text-fields/SKILL.md" rel="noopener noreferrer"&gt;Unicode text in fields you do not own&lt;/a&gt; (CC0).&lt;/p&gt;

&lt;p&gt;Checklist I actually use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Count in all three units; never show one number as if it were the limit
[ ] Truncate on code points or graphemes, never on UTF-16 indices
[ ] Normalise before validating; know whether your storage path normalises
[ ] Test rendering on a device you did not compose the text on
[ ] Disclose coverage holes instead of silently substituting another letter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The catalog those numbers were measured on is the type-style-copy tool at &lt;a href="https://fontius.app" rel="noopener noreferrer"&gt;fontius.app&lt;/a&gt;. The skill is the document; the tool is just where the 22 families live.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Research disclosure:&lt;/strong&gt; The catalog measurements come from focused local tests against the 22 shipped styles. I did not establish which unit any named third-party platform uses; that requires testing the field itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-assistance disclosure:&lt;/strong&gt; AI tools assisted with research navigation, code verification, and drafting. I reviewed the evidence and take responsibility for the claims and conclusions.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>unicode</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Everything, All at Once</title>
      <dc:creator>Sanjeev Sharma</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:28:58 +0000</pubDate>
      <link>https://dev.to/thesanjeevsharma/everything-all-at-once-50pd</link>
      <guid>https://dev.to/thesanjeevsharma/everything-all-at-once-50pd</guid>
      <description>&lt;p&gt;&lt;em&gt;By the end of this post, you'll learn how I work faster with coding agents and run more work in parallel.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Development looks very different form a year ago.&lt;/p&gt;

&lt;p&gt;I can't remember the last time I wrote a line of code myself. Over time, I've built workflows and systems that let me trust agents with much more of the development process.&lt;/p&gt;

&lt;p&gt;I was also fortunate to start working on a large greenfield project right when agentic coding started picking up. For the project, I intentionally chose popular, battle-tested tools like shadcn, Tailwind, and React Query. They're well documented and widely used, so agents already understand most of the patterns around them.&lt;/p&gt;

&lt;p&gt;The project had six frontend developers working on it at its peak —  the largest frontend team I've worked with on a single project. While the team was building features, I was working on our custom coding agent. &lt;/p&gt;

&lt;p&gt;After multiple iterations, it can now gather requirements from Jira, Slack threads or Figma, implement a feature, write tests, resolve PR comments, fix CI issues and ship to staging for review — all without a human in the loop.&lt;/p&gt;

&lt;p&gt;And we've started shipping a lot more code because of it. It has reached a point where one of the most common questions in my team is — &lt;strong&gt;"How can I work on multiple things in parallel?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But before you start running five agents at once, you need a good workflow for running one.&lt;/p&gt;

&lt;p&gt;Here's how I approach both.&lt;/p&gt;




&lt;h3&gt;
  
  
  Working on a Single Feature, But Better
&lt;/h3&gt;

&lt;p&gt;Let's say you're working on building a login feature end to end.&lt;/p&gt;

&lt;p&gt;You don't jump into dev right away, you'd probably ask your agent to write a spec for you. Most devs would run an agent and ask it to implement the spec. The agent would most likely finish it but it takes a lot more time and you only see the result in the end.&lt;/p&gt;

&lt;p&gt;Here's how I'd do it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I will ask my agent to write a technical spec. This will involve exploring the codebase and coming up with contracts. This is where I would agree on the seams and review the contracts between different modules — UI, Redux/RQ, APIs and DB schema.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, I would ask my agent to break down the spec in phases, where each phase is verifiable by me or the agent itself. Also, I'd ask my agent to tag the phases based on whether they can be worked on in parallel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I'd ask the agent to implement the plan and also let it run subagents for parallel work.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Note: I store the spec and phased-plan somewhere. Usually, I store it in a &lt;code&gt;.tmp&lt;/code&gt; directory in my codebase. This is important if I wanna run multiple agent sessions for a large piece of work. I've added &lt;code&gt;.tmp&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt; so it only lives on my system and isn't tracked.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have skills for all these steps, so I don't hand hold my agent every time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffms5kd9z6bti65x9qt00.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffms5kd9z6bti65x9qt00.png" alt="Parallel Agents" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This workflow not only gives me more time back but also gives me the confidence that the agent has built what we both initially agreed upon.&lt;/p&gt;




&lt;p&gt;I've been building &lt;a href="//flowflight.app"&gt;flowflight&lt;/a&gt; — a focus timer for  coding with music or white noise. Give it a try if that sounds like your thing. ❤️&lt;/p&gt;




&lt;h3&gt;
  
  
  Working on Multiple Features, At Once
&lt;/h3&gt;

&lt;p&gt;This is the next phase. &lt;/p&gt;

&lt;p&gt;You've figured out how to build one feature well. Now it's time to run parallel agents for different features at the same time.&lt;/p&gt;

&lt;p&gt;But one codebase can only have a single branch checked out. So how do you work on different features?&lt;/p&gt;

&lt;p&gt;A few months ago, when I ran into this exact problem, I made a copy of my codebase and opened two editors. It became messy pretty quickly, and I thought there had to be a better way.&lt;/p&gt;

&lt;p&gt;That's when I found Git Worktrees!&lt;/p&gt;

&lt;p&gt;Worktrees have been around since 2015, but they've got more relevant recently when the world started moving faster with agentic coding.&lt;/p&gt;

&lt;p&gt;Let's say you're working on the same login feature and you've got an urgent hotfix to ship. Traditionally, you'd stash your work, check out a different branch, deploy your fix, come back to your branch and pop your stash back. This is okay but it can be better — faster!&lt;/p&gt;

&lt;p&gt;Here's how I'd do it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a worktree. (without stashing my work)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../hotfix-tree &lt;span class="nt"&gt;-b&lt;/span&gt; hotfix main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will instantly create a directory beside my current working directory and create a new branch &lt;code&gt;hotfix&lt;/code&gt; based on &lt;code&gt;main&lt;/code&gt;. I can open it in another editor, fix the issue, and push it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;code ../hotfix-tree
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix: add validation for email"&lt;/span&gt;
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once I'm done, I can remove the worktree from my original directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree remove ../hotfix-tree
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;And this isn't limited to bug fixes.&lt;/p&gt;

&lt;p&gt;You can create multiple worktrees and run an agent inside each one, with every agent working idependently on a different feature.&lt;/p&gt;

&lt;p&gt;It's basically multiple branches, checked out and worked on at the same time.&lt;/p&gt;

&lt;p&gt;A few things to keep in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Each worktree will have its own copy of dependencies, so you may run into disk space issues.&lt;/li&gt;
&lt;li&gt;Git prevents you from checking out the same branch in multiple worktrees. This is to prevent data corruption.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;I hope this post makes your workflow better and you ship at lot more code faster. Happy building! ✌️&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>agents</category>
      <category>coding</category>
    </item>
    <item>
      <title>I Built an Open-Source AWS Cloud Security tool for solo devs &amp; founders !</title>
      <dc:creator>Kavee</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:27:53 +0000</pubDate>
      <link>https://dev.to/kavee-dev/i-built-an-open-source-aws-cloud-security-tool-for-solo-devs-founders--58f7</link>
      <guid>https://dev.to/kavee-dev/i-built-an-open-source-aws-cloud-security-tool-for-solo-devs-founders--58f7</guid>
      <description>&lt;p&gt;If you're a solo dev running your own AWS account with no security team, you've probably had this thought: is my IAM setup actually fine, or did I just get lucky? Plexavo exists to answer that for people in that exact position, not for teams that already have Wiz.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it does&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install plexavo&lt;br&gt;
plexavo scan --profile prod --report-html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Scans IAM, S3, EC2, and networking for misconfigurations and privilege escalation paths. Returns a 0-100 score and a plain-English report: what's wrong, what an attacker does with it, the exact command to fix it. Runs on your own local credentials zero telemetry, nothing leaves your machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A RESULT OF A REAL FINDING&lt;/strong&gt; - &lt;a href="https://plexavo.com/sample-report" rel="noopener noreferrer"&gt;https://plexavo.com/sample-report&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why it's deterministic, not AI&lt;/p&gt;

&lt;p&gt;Detection is pure Python/boto3 no model decides what counts as a finding. A security scanner that hallucinates a finding doesn't just get something wrong, it gets uninstalled and never trusted again. There's an optional AI layer (your own API key) that rewrites findings into plainer language, but it never decides what's flagged, and it's fully opt-in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it, break it, tell me&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Run it against your own account I'd rather hear what it flagged (or where it broke) than get a star.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contribute issues and PRs are genuinely welcome, it's early (v0.1.2) and there's a lot still to build.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Review the code deterministic checks mean you can actually audit what it's doing, not just trust it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contact me directly if you want to talk about it happy to answer anything.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; - &lt;a href="https://github.com/plexavo/Plexavo" rel="noopener noreferrer"&gt;https://github.com/plexavo/Plexavo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>security</category>
      <category>automation</category>
    </item>
    <item>
      <title>Debugging Is the Killer App for Free Model Tokens — Here's the Workflow</title>
      <dc:creator>Dakota Liu</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:21:08 +0000</pubDate>
      <link>https://dev.to/devrs_9381/debugging-is-the-killer-app-for-free-model-tokens-heres-the-workflow-1fda</link>
      <guid>https://dev.to/devrs_9381/debugging-is-the-killer-app-for-free-model-tokens-heres-the-workflow-1fda</guid>
      <description>&lt;p&gt;Most developers treat free model tokens as a code generation budget. They ask for snippets, refactors, and explanations, then wonder why the tokens disappear without making their codebase measurably better. I think the highest-leverage use is debugging. A model that reads your error logs and produces a ranked list of hypotheses can save you more time than any code snippet it generates, because debugging is where developers lose hours to tasks that are pattern-matching, not reasoning. This article shows a reproducible workflow for turning free model tokens into a debugging assistant, using an OpenAI-compatible endpoint and a few lines of Python.&lt;/p&gt;

&lt;p&gt;The argument isn't that code generation is useless. It's that code generation produces artifacts you still have to review, test, and integrate, while debugging produces a diagnosis you can immediately act on. The marginal value of a correct diagnosis is higher than the marginal value of a correct snippet, because the diagnosis unblocks you and the snippet only starts your work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Debugging Is the Right Job for Free Model Tokens
&lt;/h2&gt;

&lt;p&gt;Debugging is fundamentally a pattern-matching exercise. You have a stack trace, a log message, and a set of known failure modes. The model has seen thousands of similar errors during training, so it can quickly map your symptoms to likely causes. That's a different skill from writing a feature from scratch, where the model has to invent something new.&lt;/p&gt;

&lt;p&gt;Debugging also benefits from the model's ability to hold context. You can feed it the error, the surrounding code, and your recent changes, and it will connect dots that you might miss after hours of staring at the same screen. The feedback loop is fast: you try a hypothesis, and if it's wrong, you ask a follow-up question with more context.&lt;/p&gt;

&lt;p&gt;Finally, debugging is expensive. Every hour you spend chasing a bug is an hour you're not shipping features. If a model can cut that time in half, it's worth more than a hundred generated functions that you still have to test.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Workflow: From Error Log to Ranked Hypotheses
&lt;/h2&gt;

&lt;p&gt;The workflow has five steps, and only the last one spends tokens.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Collect the logs.&lt;/strong&gt; Pull the last hour of logs from your application, or the log file from the failed run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract the error block.&lt;/strong&gt; Find the most recent exception or error. Include a few lines of context before the stack trace, and the full trace itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a prompt.&lt;/strong&gt; The prompt should contain the error block, a hint about your project structure, and a request for ranked hypotheses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Call the model.&lt;/strong&gt; Use an OpenAI-compatible endpoint. The script below does this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify the top hypothesis.&lt;/strong&gt; Try the fix. If it doesn't work, ask the model a follow-up with the new error message.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key is to give the model enough context. A bare stack trace often isn't enough. Add the function names, the values of key variables, and any recent changes you made.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Reproducible Script
&lt;/h2&gt;

&lt;p&gt;Here's a minimal Python script that implements this workflow. It reads a log file, extracts the last error block, and calls a model to get ranked hypotheses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;debug_assistant.py — use a free model to analyze error logs.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_error_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Traceback&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;max_lines&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;log_text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DEBUG_MODEL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DEBUG_BASE_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DEBUG_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;choices&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;log_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error.log&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;error_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_error_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;You are a debugging assistant. Analyze the following error log from a Python application and provide:
1. The most likely root cause(s), ranked by probability.
2. A specific fix for each, with code if applicable.
3. Any additional logging or checks that would confirm the diagnosis.

Error log:
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error_block&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

Project context (from environment):
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DEBUG_PROJECT_CONTEXT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No additional context provided.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

Be concise. Output as a numbered list.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DEBUG_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://your-endpoint.example.com/v1"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DEBUG_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-key"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DEBUG_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-model"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DEBUG_PROJECT_CONTEXT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"FastAPI app with PostgreSQL and Redis"&lt;/span&gt;
python debug_assistant.py app.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script is intentionally simple. It doesn't handle multi-file logs or interactive follow-ups, but it's enough to show the pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Free Server Makes This Practical
&lt;/h2&gt;

&lt;p&gt;Debugging is interactive. You'll often make multiple calls per session, refining the prompt as you learn more. That's where cost becomes a barrier. If you're paying per call, you might hesitate to ask a follow-up question. A free server removes that hesitation.&lt;/p&gt;

&lt;p&gt;MonkeyCode is an open-source project that provides free model access and a free server option, with 10 million free tokens in the current offering. That's enough for thousands of debugging sessions. The endpoint is OpenAI-compatible, so the script above works without modification.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;I'm repeating those availability claims as provided by the project, not as verified by my own stress testing. Quotas, uptime, and terms can change, so check the current details before you wire this into a production pipeline. The script itself is endpoint-agnostic; if you switch providers, the only change is the base URL and key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and Who Should Skip This
&lt;/h2&gt;

&lt;p&gt;This workflow has real limits. The model can hallucinate plausible-sounding causes that have nothing to do with your bug. Always verify before changing code. It also can't see your entire system; it only knows what you put in the prompt. If you omit a key detail, the diagnosis will be wrong.&lt;/p&gt;

&lt;p&gt;Security matters. If your logs contain customer data or secrets, don't send them to a third-party model. Run a local model or sanitize the logs first.&lt;/p&gt;

&lt;p&gt;Skip this workflow if your project has no logging, if you're working in a tightly coupled legacy system where context is too large to summarize, or if you're debugging a race condition that requires reproducing the exact timing. Models are better at logical errors than concurrency issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Position
&lt;/h2&gt;

&lt;p&gt;Free model tokens are a scarce resource, and scarcity demands prioritization. Code generation is a nice-to-have; debugging is a must-have. Every hour you save on debugging is an hour you can spend on the work that actually matters. So next time you hit a mysterious error, don't just copy the stack trace into a search engine. Feed it to a free model and let it rank the hypotheses. The first time it points you to a root cause you'd have missed, you'll be convinced.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>debugging</category>
      <category>python</category>
      <category>productivity</category>
    </item>
    <item>
      <title>VeloxDB : database admin tool for Linux</title>
      <dc:creator>abeni16</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:20:55 +0000</pubDate>
      <link>https://dev.to/abeni16/veloxdb-database-admin-tool-for-linux-7l9</link>
      <guid>https://dev.to/abeni16/veloxdb-database-admin-tool-for-linux-7l9</guid>
      <description>&lt;p&gt;VeloxDB is an open-source database management tool built with Rust and Tauri 2, available for Linux as .deb and .AppImage packages (x64 and ARM64).&lt;/p&gt;

&lt;p&gt;It supports 6 database engines — PostgreSQL, MySQL, MongoDB, Redis, SQLite, and DuckDB — plus wire-compatible cloud services like Supabase, PlanetScale, and Atlas. Connections work by pasting any standard URI (postgresql://, mysql://, redis://, mongodb(+srv)://, sqlite://), with engine, host, port, and credentials auto-detected.&lt;/p&gt;

&lt;p&gt;Other features: schema-aware SQL autocomplete, a visual ER diagram designer (drag-and-drop, migration generation, export to SQL/PNG/PDF), SSH tunneling, SSL/TLS support, and an inferred schema view for MongoDB collections and Redis keys.&lt;/p&gt;

&lt;p&gt;Since it's built with Tauri instead of Electron, the download is 17–30MB and memory usage stays around ~50MB. No telemetry, everything runs locally.&lt;/p&gt;

&lt;p&gt;MIT licensed. Site: &lt;a href="https://veloxdb.dev" rel="noopener noreferrer"&gt;visit here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>database</category>
      <category>linux</category>
    </item>
    <item>
      <title>Dynamic Programming: The Matrix of Patterns</title>
      <dc:creator>Timevolt</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:20:43 +0000</pubDate>
      <link>https://dev.to/timevolt/dynamic-programming-the-matrix-of-patterns-4aha</link>
      <guid>https://dev.to/timevolt/dynamic-programming-the-matrix-of-patterns-4aha</guid>
      <description>&lt;h2&gt;
  
  
  The Quest Begins (The "Why")
&lt;/h2&gt;

&lt;p&gt;I still remember the first time I saw a dynamic programming question pop up on a whiteboard during an interview. The problem was simple: &lt;em&gt;given an array of integers, find the contiguous subarray with the largest sum&lt;/em&gt;. My brain went straight to the brute‑force idea—check every possible start and end, keep the best sum. Two nested loops, O(n²) time, and a sinking feeling that I was about to waste twenty minutes of the interviewer’s patience. I coded it, ran a few test cases, and watched the runtime blow up on larger inputs. It felt like trying to defeat a boss by swinging a sword at its feet over and over—ineffective and exhausting.  &lt;/p&gt;

&lt;p&gt;I knew there had to be a smarter way, but the explanations I found online jumped straight into the code without ever telling me &lt;em&gt;why&lt;/em&gt; the trick works. I wanted to understand the underlying logic, not just memorize a pattern. That curiosity turned into a mini‑quest: uncover the secret behind linear‑time DP solutions and share it with anyone who’s ever stared at a nested loop and wondered, “There’s gotta be a better way.”  &lt;/p&gt;

&lt;h2&gt;
  
  
  The Revelation (The Insight)
&lt;/h2&gt;

&lt;p&gt;The breakthrough came when I stopped thinking about “subarrays” and started thinking about &lt;em&gt;decisions&lt;/em&gt;. For each position &lt;em&gt;i&lt;/em&gt; in the array, there are only two meaningful choices for the best subarray that ends exactly at &lt;em&gt;i&lt;/em&gt;:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start a new subarray&lt;/strong&gt; at &lt;em&gt;i&lt;/em&gt; (the sum is just nums[i]).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extend the best subarray that ended at *i‑1&lt;/strong&gt;* by adding nums[i] to it.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we already know the maximum sum of a subarray that ends at &lt;em&gt;i‑1&lt;/em&gt;, we can compute the answer for &lt;em&gt;i&lt;/em&gt; in constant time. That’s the heart of optimal substructure: the solution to a problem depends only on the solution to a smaller, overlapping subproblem. And because we reuse the same computation for every index, we avoid the exponential blow‑up of naive recursion—classic overlapping subproblems.  &lt;/p&gt;

&lt;p&gt;Mathematically, we define &lt;code&gt;dp[i]&lt;/code&gt; as the maximum sum of a subarray that ends at index &lt;em&gt;i&lt;/em&gt;. The recurrence is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why does this work?  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;nums[i]&lt;/code&gt; alone is bigger than extending the previous subarray, then any optimal subarray ending at &lt;em&gt;i&lt;/em&gt; must start at &lt;em&gt;i&lt;/em&gt; (otherwise we’d be dragging a negative or useless prefix).
&lt;/li&gt;
&lt;li&gt;Otherwise, the best we can do is to take the best ending at &lt;em&gt;i‑1&lt;/em&gt; and tack on nums[i]; dropping the prefix would only make the sum smaller.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice we never need to look beyond the immediate predecessor. That means we can keep just one variable instead of an entire array, turning the space complexity from O(n) to O(1). Each element is processed once, giving us O(n) time—linear, clean, and ready for interview whiteboards.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Wielding the Power (Code &amp;amp; Examples)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Struggle: Brute Force
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;max_subarray_bruteforce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-inf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two loops, O(n²) time. It works, but it feels like hammering a nail with a screwdriver—technically possible, painfully slow.  &lt;/p&gt;

&lt;h3&gt;
  
  
  The Victory: Kadane’s DP
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;max_subarray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Handles the all‑negative case by starting with the first element
&lt;/span&gt;    &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
        &lt;span class="c1"&gt;# Either start fresh at x, or extend the previous segment
&lt;/span&gt;        &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. Four lines inside the loop, constant extra space, linear time.  &lt;/p&gt;

&lt;h4&gt;
  
  
  Common Traps
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting the all‑negative case&lt;/strong&gt; – If you initialise &lt;code&gt;best = 0&lt;/code&gt;, the algorithm would incorrectly return 0 for an array like &lt;code&gt;[-3, -2, -7]&lt;/code&gt;. Starting with the first element fixes that.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mis‑placing the reset&lt;/strong&gt; – Some try to reset &lt;code&gt;current&lt;/code&gt; to 0 when it drops below zero. That works only when you know the answer isn’t negative; safer to stick to the recurrence &lt;code&gt;current = max(x, current + x)&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A Second Interview Flavor: Best Time to Buy and Sell Stock
&lt;/h3&gt;

&lt;p&gt;The same DP pattern appears in LeetCode 121: &lt;em&gt;max profit from one buy‑sell transaction&lt;/em&gt;. Think of &lt;code&gt;price[i]&lt;/code&gt; as the “cost” of holding a stock up to day &lt;em&gt;i&lt;/em&gt;. The profit if we sell today is &lt;code&gt;price[i] - min_price_so_far&lt;/code&gt;. We keep the smallest price seen so far (the “best buy”) and compute the best sell profit in one pass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;max_profit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;min_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;max_profit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;min_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# best buy up to today
&lt;/span&gt;        &lt;span class="n"&gt;max_profit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_profit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;min_price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# best sell today
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;max_profit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, O(n) time, O(1) space, and the same “look only at the previous step” intuition.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Why This New Power Matters
&lt;/h2&gt;

&lt;p&gt;Once you see the DP lens—&lt;em&gt;optimal substructure + overlapping subproblems&lt;/em&gt;—a whole family of problems clicks into place:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maximum sum subarray with at least one element&lt;/strong&gt; (the classic we just solved).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Longest alternating subarray&lt;/strong&gt; (track two states: expecting up or down).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimum path sum in a grid&lt;/strong&gt; (each cell depends only on top or left neighbor).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;String edit distance&lt;/strong&gt; (though that’s O(n*m), the same principle).
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The beauty is that you stop memorising “templates” and start &lt;em&gt;deriving&lt;/em&gt; them. When you encounter a new problem, ask: &lt;em&gt;What decision am I making at position *i&lt;/em&gt;? What’s the smallest piece of information I need from the past to make that decision optimally?* If the answer is a constant‑sized summary (like a max, a min, or a bool), you’ve got a linear‑time DP waiting to be written.  &lt;/p&gt;

&lt;p&gt;This shift turns interview anxiety into excitement. Instead of dreading the nested‑loop trap, you’ll spot the recurrence, write the clean loop, and watch the interviewer’s eyes light up.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Your Turn
&lt;/h2&gt;

&lt;p&gt;Grab a piece of paper (or your favorite IDE) and try this:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Given an array &lt;code&gt;nums&lt;/code&gt;, find the maximum sum of a subarray &lt;strong&gt;that must contain at least one negative number&lt;/strong&gt;. If no such subarray exists, return the maximum element.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hint: you’ll need to keep two DP states—one for the best sum ending at &lt;em&gt;i&lt;/em&gt; that has seen a negative, and one for the best sum that hasn’t.  &lt;/p&gt;

&lt;p&gt;Drop your solution in the comments, share a “aha!” moment, or just tell me which DP pattern made you feel like you finally leveled up. Let’s keep the quest going—because every linear‑time loop you write is another boss defeated. Happy coding!&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>programming</category>
      <category>coding</category>
    </item>
    <item>
      <title>The CSS bug that taught me JS-injected styles always win</title>
      <dc:creator>Nogan's Development</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:20:27 +0000</pubDate>
      <link>https://dev.to/nogandev/the-css-bug-that-taught-me-js-injected-styles-always-win-2io2</link>
      <guid>https://dev.to/nogandev/the-css-bug-that-taught-me-js-injected-styles-always-win-2io2</guid>
      <description>&lt;p&gt;I spent way longer than I'd like to admit chasing a dark mode bug that made zero sense on paper.&lt;/p&gt;

&lt;p&gt;I'm building WidgetForge, a drop-in AI chat widget you can paste into any site — static HTML or Next.js, pick a theme, done. Four themes, one shared JS core. Nothing exotic.&lt;/p&gt;

&lt;p&gt;Except one small piece of it kept breaking dark mode, and I couldn't figure out why.&lt;/p&gt;

&lt;p&gt;The setup&lt;/p&gt;

&lt;p&gt;Every message in the chat has little icons — a voice note badge, status icons, that kind of thing. I wanted those to invert properly in dark mode, so I wrote the obvious CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.voice-message-icon&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;invert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;brightness&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dropped it in the theme's style.css. Tested it. Worked fine in isolation.&lt;/p&gt;

&lt;p&gt;Then I wired it into the actual widget and dark mode just... didn't apply. Same class name, same media query, same browser. No console errors. No typos I could find. It was the kind of bug where everything looks correct, which is the most annoying kind.&lt;/p&gt;

&lt;p&gt;Where it actually was&lt;/p&gt;

&lt;p&gt;Here's the thing I didn't clock at first: this specific icon isn't rendered from the static HTML at all. It's built at runtime, in JS, when a voice message gets added to the chat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;injectVoiceMessageStyles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;voice-message-badge-styles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;style&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;voice-message-badge-styles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    .voice-message-icon {
      width: 16px;
      height: 16px;
      object-fit: contain;
      flex-shrink: 0;
    }
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your styles are partly generated by JS at runtime — dynamically injected &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tags, CSS-in-JS, whatever — treat that as its own independent stylesheet. It doesn't matter how well-organized your "real" CSS file is if a script is appending a competing block after it loads. External stylesheets are static and load once; JS-injected blocks can show up whenever, and they'll happily override anything sitting above them in the cascade.&lt;/p&gt;

&lt;p&gt;Once I knew to look for this pattern, I found two more spots in the same codebase doing the same thing — dynamically created UI elements with their own injected styles that had quietly drifted out of sync with the main theme file. Same fix each time: move the state-dependent rules into the block that's actually authoritative for that element.&lt;/p&gt;

&lt;p&gt;Small bug, but it changed how I think about where styling logic should live once JS starts generating markup at runtime.&lt;/p&gt;

&lt;p&gt;WidgetForge is a self-hosted AI chat widget — static HTML or Next.js, four themes, no database, no build step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chatbot-temp-nine.vercel.app/" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nogan2.gumroad.com/l/widgetforge" rel="noopener noreferrer"&gt;Get the full template&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Making AI Coding Agents More Efficient: My Local Toolkit</title>
      <dc:creator>Ammar Najjar</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:17:43 +0000</pubDate>
      <link>https://dev.to/ammarnajjar/making-ai-coding-agents-more-efficient-my-local-toolkit-86n</link>
      <guid>https://dev.to/ammarnajjar/making-ai-coding-agents-more-efficient-my-local-toolkit-86n</guid>
      <description>&lt;p&gt;Giving AI coding agents more tools doesn’t necessarily make them more efficient.&lt;/p&gt;

&lt;p&gt;After using OpenCode and Claude Code heavily, I started focusing less on adding capabilities and more on controlling the information flowing into the agent.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;searching before reading entire files&lt;/li&gt;
&lt;li&gt;choosing between text, structural, and semantic search&lt;/li&gt;
&lt;li&gt;reducing noisy command output&lt;/li&gt;
&lt;li&gt;keeping sessions focused&lt;/li&gt;
&lt;li&gt;defining explicit stopping rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve documented the toolkit I currently use, including Headroom, RTK, Caveman, Serena, &lt;code&gt;rg&lt;/code&gt;, &lt;code&gt;fd&lt;/code&gt;, &lt;code&gt;ast-grep&lt;/code&gt;, &lt;code&gt;jq&lt;/code&gt;, &lt;code&gt;yq&lt;/code&gt;, and others, along with how I define their responsibilities in &lt;code&gt;AGENTS.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The principle behind all of it is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Give the agent the smallest amount of information necessary to make the next correct decision.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Full post:&lt;br&gt;
&lt;a href="https://ammar-najjar.com/blog/local-ai-coding-toolkit/" rel="noopener noreferrer"&gt;https://ammar-najjar.com/blog/local-ai-coding-toolkit/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>devtools</category>
    </item>
    <item>
      <title>I measured 20 "free dofollow" backlink sites. One of them was real.</title>
      <dc:creator>Linkhiver developer</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:15:32 +0000</pubDate>
      <link>https://dev.to/linkhiver_developer_799c5/i-measured-20-free-dofollow-backlink-sites-one-of-them-was-real-4hck</link>
      <guid>https://dev.to/linkhiver_developer_799c5/i-measured-20-free-dofollow-backlink-sites-one-of-them-was-real-4hck</guid>
      <description>&lt;p&gt;I run a small link-in-bio SaaS. Like every other founder with a new domain and no authority, I went looking for the "100 free dofollow backlink sites" lists.&lt;/p&gt;

&lt;p&gt;So I wrote a script and checked them. Twenty platforms, one at a time, on real published pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exactly one of them gives a free user a followed, indexable link.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not because the lists lie about &lt;code&gt;rel&lt;/code&gt;. They're often right about &lt;code&gt;rel&lt;/code&gt;. They're just measuring the wrong thing — and the way they're wrong is interesting enough to be worth writing down, because the same four failure modes explain almost every result.&lt;/p&gt;

&lt;h2&gt;
  
  
  The script
&lt;/h2&gt;

&lt;p&gt;Nothing clever. Fetch a real published listing page, pull the robots meta, the canonical, and the &lt;code&gt;rel&lt;/code&gt; of every outbound anchor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# gate.sh &amp;lt;url&amp;gt;&lt;/span&gt;
&lt;span class="nv"&gt;U&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;UA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
(KHTML, like Gecko) Chrome/126.0 Safari/537.36"&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$UA&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /tmp/body.html &lt;span class="nt"&gt;--max-time&lt;/span&gt; 25 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$U&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-io&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;meta[^&amp;gt;]*name=["'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;']robots["'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'][^&amp;gt;]*&amp;gt;'&lt;/span&gt; /tmp/body.html | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-3&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-io&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;link[^&amp;gt;]*rel=["'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;']canonical["'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'][^&amp;gt;]*&amp;gt;'&lt;/span&gt; /tmp/body.html | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-2&lt;/span&gt;

perl &lt;span class="nt"&gt;-0777&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; &lt;span class="s1"&gt;'while(/&amp;lt;a\b([^&amp;gt;]*href=["\x27](https?:\/\/[^"\x27]+)["\x27][^&amp;gt;]*)&amp;gt;/gi){
  $attr=$1; $href=$2;
  $rel = ($attr=~/rel=["\x27]([^"\x27]*)["\x27]/i) ? $1 : "NO-REL(dofollow)";
  print "$rel\t$href\n";
}'&lt;/span&gt; /tmp/body.html | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it against a competitor's listing, not your own — you want to see what the platform actually publishes, not what it promises.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure mode 1: the page is dofollow and noindex
&lt;/h2&gt;

&lt;p&gt;The link is followed. The page it lives on is not in the index. Nothing flows.&lt;/p&gt;

&lt;p&gt;Two of the most-recommended "free dofollow" platforms do this to free accounts specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A popular hosted-changelog product gives you a public changelog page with genuinely followed links. The free plan force-&lt;code&gt;noindex&lt;/code&gt;es that page. Indexing is a paid upgrade.&lt;/li&gt;
&lt;li&gt;A large GIF platform's brand channels render the website field as &lt;code&gt;rel="noopener noreferrer"&lt;/code&gt; — followed. User channels stay &lt;code&gt;noindex&lt;/code&gt; until the brand is verified.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both were on every list I read. Neither list mentioned the robots meta. &lt;strong&gt;&lt;code&gt;rel&lt;/code&gt; on a &lt;code&gt;noindex&lt;/code&gt; page is worth nothing&lt;/strong&gt;, and no &lt;code&gt;rel&lt;/code&gt; checker will tell you that, because it isn't looking at the head.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure mode 2: the canonical points somewhere else
&lt;/h2&gt;

&lt;p&gt;This one is nastier because the page passes both obvious checks.&lt;/p&gt;

&lt;p&gt;One well-known developer-tools directory serves &lt;code&gt;robots: index, follow&lt;/code&gt; on its tool pages, and the vendor link is &lt;code&gt;rel="noopener noreferrer"&lt;/code&gt; — followed. Perfect, on the surface.&lt;/p&gt;

&lt;p&gt;Every single tool page also serves:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://thatdirectory.example/"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Homepage. Site-wide. Your page tells Google "I am the homepage." A canonical is a strong hint, and while Google can reject it, you are betting your link on that rejection. I could not prove those pages get indexed independently, and I'm not going to claim they do.&lt;/p&gt;

&lt;p&gt;Check the canonical. It takes one grep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure mode 3: the dofollow you measured was a paid listing
&lt;/h2&gt;

&lt;p&gt;This is the one that got me, and it's the reason I'm writing this.&lt;/p&gt;

&lt;p&gt;I measured three launch platforms with the script. All three: followed vendor links, indexable pages. I wrote them up as "do this."&lt;/p&gt;

&lt;p&gt;Then I actually submitted to one. The confirmation email listed &lt;strong&gt;"do-follow backlinks"&lt;/strong&gt; as a benefit of the $49 tier.&lt;/p&gt;

&lt;p&gt;Go back and look at the others with that in mind and the pattern is obvious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One directory's &lt;em&gt;product&lt;/em&gt; links are &lt;code&gt;rel="nofollow noopener noreferrer"&lt;/code&gt;, while the sponsor slots on the very same page are &lt;code&gt;rel="noopener"&lt;/code&gt; — followed. Same HTML, same template, two different link policies, sorted by who paid.&lt;/li&gt;
&lt;li&gt;Another platform's free tier requires a reciprocal badge on your own site. Not one of the five followed listings I sampled had that badge anywhere on their site — meaning those five almost certainly weren't free listings at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So there's a fourth gate, and it's the one nobody checks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;rel&lt;/code&gt; · &lt;code&gt;robots&lt;/code&gt; · canonical · &lt;em&gt;and which pricing tier was the page you measured published under?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A live page's &lt;code&gt;rel&lt;/code&gt; is evidence about &lt;em&gt;that&lt;/em&gt; listing. It is not evidence about &lt;em&gt;yours&lt;/em&gt;. You often cannot know until your own page goes live — which means the honest answer for a queued free submission is "unproven," not "dofollow."&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure mode 4: there is no link at all
&lt;/h2&gt;

&lt;p&gt;Worth checking before you spend an hour on a submission form:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A large software-comparison site: &lt;code&gt;index, follow&lt;/code&gt;, self-canonical, dedicated category pages, comparison pages — and &lt;strong&gt;zero&lt;/strong&gt; outbound anchors to the vendor. The whole page is about the product and never links to it.&lt;/li&gt;
&lt;li&gt;A startup directory whose homepage is full of followed outbound links (they're sponsor slots) while the permanent detail page for each listing links nowhere.&lt;/li&gt;
&lt;li&gt;An integrations marketplace with a page per app and no link to the app's own site.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And two that block it at a completely different layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A PR-source platform's expert directory looked like a free profile with a website field. Its &lt;code&gt;robots.txt&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;  &lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: *
  &lt;span class="n"&gt;Disallow&lt;/span&gt;: /&lt;span class="n"&gt;profile&lt;/span&gt;/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every profile URL is also signed with a token and redirects to the login page without one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The WordPress.org plugin directory. Everyone "knows" it's a high-authority free dofollow. Every vendor link on a plugin page is &lt;code&gt;rel="nofollow ugc"&lt;/code&gt;. Writing a plugin can be great distribution. It is not a link.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The scoreboard
&lt;/h2&gt;

&lt;p&gt;Twenty platforms where I could measure what a free account actually gets:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Followed &lt;strong&gt;and&lt;/strong&gt; indexable &lt;strong&gt;and&lt;/strong&gt; actually free&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Followed but &lt;code&gt;noindex&lt;/code&gt; on the free plan&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Followed but canonicalized away&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Followed only on paid listings (or unproven for free)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nofollow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No outbound link at all&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blocked by &lt;code&gt;robots.txt&lt;/code&gt; / no crawlable page&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The one that passed everything was a plain software directory with a normal listing, no upsell attached to the link, and no reciprocal-badge condition. It is also, per Bing Webmaster Tools, the only legitimate referring domain my site has.&lt;/p&gt;

&lt;h2&gt;
  
  
  A mistake I made, so you don't
&lt;/h2&gt;

&lt;p&gt;Seven platforms returned &lt;code&gt;403&lt;/code&gt; or &lt;code&gt;429&lt;/code&gt; to curl. Their block pages helpfully serve:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"robots"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"noindex, nofollow"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I nearly recorded that as the verdict. &lt;strong&gt;That's the block page's meta, not the real page's.&lt;/strong&gt; I wrote one platform off as dead on a &lt;code&gt;429&lt;/code&gt; — then opened it in a logged-in browser and found a live product with 606 open queries in it.&lt;/p&gt;

&lt;p&gt;If a bot wall stops you, the honest status is "unmeasured." Open it in a real browser or leave the row blank.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd actually do instead
&lt;/h2&gt;

&lt;p&gt;The pattern across all twenty is consistent enough to be a rule: &lt;strong&gt;modern directories nofollow the free listing and sell the dofollow.&lt;/strong&gt; That isn't a conspiracy, it's a business model, and it means grinding a list of 100 directories is a way to spend fifty hours building the exact footprint you'll later disavow.&lt;/p&gt;

&lt;p&gt;For context on why that matters to me: my domain has ~103 referring domains and &lt;strong&gt;104&lt;/strong&gt; entries on its disavow file. The list-driven approach is how you get there.&lt;/p&gt;

&lt;p&gt;What's left, once you take the directories out, is unglamorous: write things worth citing, answer questions where you genuinely have first-hand data, and get covered by publications your audience actually reads. Editorial links carry no &lt;code&gt;rel&lt;/code&gt; at all — I checked a national tech publication's articles while writing this, and every outbound link in the body was bare.&lt;/p&gt;

&lt;p&gt;Slower. But there's no tier that takes it away from you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm building &lt;a href="https://linkhiver.com" rel="noopener noreferrer"&gt;Linkhiver&lt;/a&gt;, a link-in-bio tool localized in seven languages. The measurements above come from doing this badly for my own domain first.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>startup</category>
      <category>marketing</category>
    </item>
    <item>
      <title>Your Computer Is Busy When You're Not: Building a Desktop Observability Tool with Electron</title>
      <dc:creator>Nishikanta Ray</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:14:54 +0000</pubDate>
      <link>https://dev.to/nishikantaray/your-computer-is-busy-when-youre-not-building-a-desktop-observability-tool-with-electron-1m6k</link>
      <guid>https://dev.to/nishikantaray/your-computer-is-busy-when-youre-not-building-a-desktop-observability-tool-with-electron-1m6k</guid>
      <description>&lt;p&gt;You close your laptop.&lt;/p&gt;

&lt;p&gt;The screen goes dark.&lt;/p&gt;

&lt;p&gt;You assume everything stopped.&lt;/p&gt;

&lt;p&gt;But what if it didn't?&lt;/p&gt;

&lt;p&gt;Maybe Docker is still transferring data.&lt;/p&gt;

&lt;p&gt;Maybe Chrome is still downloading something.&lt;/p&gt;

&lt;p&gt;Maybe an application is consuming CPU in the background.&lt;/p&gt;

&lt;p&gt;Maybe your computer woke up at 3 AM, performed some background work, and went back to sleep.&lt;/p&gt;

&lt;p&gt;Most operating systems already expose pieces of this information.&lt;/p&gt;

&lt;p&gt;The interesting part is putting those pieces together.&lt;/p&gt;

&lt;p&gt;That's what I wanted to explore:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Can we build an observability layer for a desktop computer using Electron?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not another CPU/RAM widget.&lt;/p&gt;

&lt;p&gt;Something that answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is my computer actually doing?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;Imagine opening your desktop monitoring application and seeing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TODAY
────────────────────────────────────

Computer active        7h 42m
Idle                   1h 13m
Sleep                  8h 05m

Network
↓ Download             6.8 GB
↑ Upload               1.2 GB

Top applications
────────────────────────────────────

VS Code                3h 42m
Chrome                 2h 18m
Docker                 1h 31m
Slack                  52m

Network-heavy apps
────────────────────────────────────

Docker                 2.4 GB
Chrome                 1.8 GB
VS Code                920 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now imagine clicking &lt;strong&gt;"What happened while I was away?"&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;18:42  User became idle
18:51  Screen locked
18:53  Docker network activity
19:07  Background sync completed
19:14  System entered sleep
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's much more interesting than a CPU percentage.&lt;/p&gt;




&lt;h2&gt;
  
  
  The npm Package That Makes This Easier
&lt;/h2&gt;

&lt;p&gt;Instead of writing native system integrations for everything ourselves, we can start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;systeminformation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;systeminformation&lt;/code&gt; provides APIs for system information, CPU, memory, battery, filesystem, network, processes, Docker and more. It also supports Linux, macOS and Windows, although individual APIs have platform-specific support.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;si&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;systeminformation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSystemStats&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currentLoad&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;networkStats&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentLoad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;percent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;network&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getSystemStats&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our Electron main process can periodically collect system information.&lt;/p&gt;




&lt;h2&gt;
  
  
  Monitoring Network Activity
&lt;/h2&gt;

&lt;p&gt;One of the most useful APIs is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;networkStats&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It provides network statistics including received/transmitted bytes and calculated per-second rates. The package calculates rates based on differences between successive calls, so the first call doesn't provide a meaningful rate yet.&lt;/p&gt;

&lt;p&gt;A simple monitor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;si&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;systeminformation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;networkStats&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;download&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rx_sec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tx_sec&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Wi-Fi
Download: 2.4 MB/s
Upload:   180 KB/s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this is only the beginning.&lt;/p&gt;




&lt;h2&gt;
  
  
  Network Connections
&lt;/h2&gt;

&lt;p&gt;We can also inspect active network connections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;networkConnections&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives us information about active TCP/UDP connections.&lt;/p&gt;

&lt;p&gt;That means we can potentially build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Active Connections
────────────────────────────

TCP    443    api.example.com
TCP    443    github.com
TCP    443    google.com
UDP    53     DNS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the dashboard starts becoming useful for troubleshooting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Which Application Is Active?
&lt;/h2&gt;

&lt;p&gt;Network traffic alone doesn't tell us &lt;strong&gt;who is responsible&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We also want to know which application the user is interacting with.&lt;/p&gt;

&lt;p&gt;One option is a native active-window module such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @jannchie/active-window
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package exposes information about the currently selected window and user idle time on supported Windows, macOS and Linux/Xorg environments. Platform coverage isn't identical everywhere, so this should be treated as an OS-dependent component.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;activeWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@jannchie/active-window&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getActiveApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;activeWindow&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getActiveWindow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;windowClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;windowName&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10:32:14  VS Code
10:32:15  VS Code
10:32:16  VS Code
...
10:45:02  Chrome
10:45:03  Chrome
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of storing every second individually, we can aggregate this into sessions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VS Code
10:32 → 10:45
Duration: 13 minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Sleep and Wake
&lt;/h2&gt;

&lt;p&gt;This is where Electron itself becomes useful.&lt;/p&gt;

&lt;p&gt;Electron provides the &lt;code&gt;powerMonitor&lt;/code&gt; module for monitoring system power-state changes, including suspend/resume, AC/battery changes, idle state and lock/unlock events on supported platforms.&lt;/p&gt;

&lt;p&gt;In the Electron main process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;powerMonitor&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;electron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;powerMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;suspend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;System is going to sleep&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;powerMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resume&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;System woke up&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can turn those events into database records:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;recordEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;powerMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;suspend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;recordEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system_sleep&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;powerMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resume&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;recordEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system_wake&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our timeline knows when the machine slept.&lt;/p&gt;




&lt;h2&gt;
  
  
  Idle Detection
&lt;/h2&gt;

&lt;p&gt;Electron also provides:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;powerMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSystemIdleTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;powerMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSystemIdleState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The latter can return states such as &lt;code&gt;active&lt;/code&gt;, &lt;code&gt;idle&lt;/code&gt;, or &lt;code&gt;locked&lt;/code&gt; on supported systems.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;powerMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSystemIdleState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;idleSeconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;powerMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSystemIdleTime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;idleSeconds&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can therefore distinguish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Active
   ↓
Idle
   ↓
Locked
   ↓
Sleep
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's much more meaningful than simply measuring application runtime.&lt;/p&gt;




&lt;h2&gt;
  
  
  Putting Everything Together
&lt;/h2&gt;

&lt;p&gt;Now imagine collecting events from four sources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Electron App
                      │
       ┌──────────────┼──────────────┐
       │              │              │
  powerMonitor   systeminformation   active-window
       │              │              │
       │         CPU / RAM / Net     Active App
       │              │              │
       └──────────────┼──────────────┘
                      ▼
                Event Collector
                      │
                      ▼
                Local Database
                      │
                      ▼
              Activity Timeline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple event model could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;network&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;docker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;downloadBytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1824000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;uploadBytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;420000&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;power&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sleep&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server.js - Visual Studio Code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now everything becomes queryable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Interesting Part: Correlation
&lt;/h2&gt;

&lt;p&gt;This is where a normal system monitor becomes a &lt;strong&gt;desktop observability tool&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose we see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;18:20  User idle
18:23  CPU 65%
18:24  Network 18 MB/s
18:26  Docker active
18:31  420 MB downloaded
18:42  Screen locked
18:45  Network still active
19:02  System sleep
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can generate an explanation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Docker continued running after the user became idle and transferred approximately 420 MB before the system entered sleep.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's an insight.&lt;/p&gt;

&lt;p&gt;Not just a metric.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Simple Collector
&lt;/h2&gt;

&lt;p&gt;We could start with something surprisingly small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;powerMonitor&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;electron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;si&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;systeminformation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currentLoad&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;networkStats&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;

    &lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;idle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;powerMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSystemIdleTime&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;idleState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;powerMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSystemIdleState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;powerMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isOnBatteryPower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentLoad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="na"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;rxPerSecond&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rx_sec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;txPerSecond&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tx_sec&lt;/span&gt;
    &lt;span class="p"&gt;}))&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five seconds later, we have the beginning of our own desktop telemetry system.&lt;/p&gt;




&lt;h2&gt;
  
  
  But Don't Collect Everything Every Second
&lt;/h2&gt;

&lt;p&gt;This is an important design decision.&lt;/p&gt;

&lt;p&gt;You don't necessarily want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Every 1 second
    ↓
Everything
    ↓
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can generate enormous amounts of useless data.&lt;/p&gt;

&lt;p&gt;Instead, use different collection intervals.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Power events        Event-driven
App changes         Event-driven
CPU                 5-10 seconds
Memory              10 seconds
Network             1-5 seconds
Connections         10-30 seconds
Daily aggregates    1 minute+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And store &lt;strong&gt;state changes&lt;/strong&gt; rather than repeated identical states.&lt;/p&gt;

&lt;p&gt;For example, don't write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10:00 VS Code
10:01 VS Code
10:02 VS Code
10:03 VS Code
10:04 VS Code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VS Code
10:00 → 10:04
Duration: 4 minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the database dramatically smaller.&lt;/p&gt;




&lt;h2&gt;
  
  
  What About Electron's Network Logging?
&lt;/h2&gt;

&lt;p&gt;If the thing you're monitoring is specifically &lt;strong&gt;your Electron application's own network traffic&lt;/strong&gt;, Electron has another useful tool: &lt;code&gt;netLog&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;netLog&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;electron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;whenReady&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;netLog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startLogging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/tmp/electron-network-log&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Electron's &lt;code&gt;netLog&lt;/code&gt; records network events for a session and supports different capture modes. Be careful with &lt;code&gt;includeSensitive&lt;/code&gt; and &lt;code&gt;everything&lt;/code&gt;, because those modes can capture sensitive information or transferred bytes.&lt;/p&gt;

&lt;p&gt;This is different from &lt;code&gt;systeminformation&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systeminformation
        ↓
Whole-system information

Electron netLog
        ↓
Your Electron application's network activity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That distinction is important.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Product I Would Build
&lt;/h2&gt;

&lt;p&gt;I wouldn't call this another "Task Manager."&lt;/p&gt;

&lt;p&gt;I'd call it something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Desktop Observability&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The dashboard could have four major views.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Activity
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VS Code       4h 12m
Chrome        2h 31m
Slack         58m
Docker        1h 42m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Network
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Download     8.4 GB
Upload       1.3 GB

Docker       3.1 GB
Chrome       2.7 GB
VS Code      1.2 GB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Power
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Active       8h 21m
Idle         1h 08m
Sleep        7h 42m

Battery used 34%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Timeline
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;09:02  Wake
09:05  VS Code
10:32  Chrome
12:14  Idle
12:31  Docker network activity
13:02  Active
18:42  Lock
19:01  Sleep
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then the killer feature:&lt;/p&gt;

&lt;h3&gt;
  
  
  Ask the computer
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Why was my laptop slow today?&lt;/p&gt;

&lt;p&gt;What used the most bandwidth?&lt;/p&gt;

&lt;p&gt;What happened while I was away?&lt;/p&gt;

&lt;p&gt;Which applications are active in the background?&lt;/p&gt;

&lt;p&gt;Did anything continue running after I locked the computer?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;A practical first version could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Electron
│
├── Main Process
│   │
│   ├── powerMonitor
│   ├── systeminformation
│   ├── active-window
│   └── netLog
│
├── Collector
│   │
│   ├── power events
│   ├── app sessions
│   ├── CPU/memory
│   └── network stats
│
├── SQLite
│
└── React Renderer
    │
    ├── Dashboard
    ├── Timeline
    ├── Applications
    ├── Network
    └── Power
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key design principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Collect locally. Correlate locally. Explain locally.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You don't need to send a user's entire computer activity to a cloud server just to tell them why their laptop was busy.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Idea
&lt;/h2&gt;

&lt;p&gt;The interesting thing here isn't &lt;code&gt;systeminformation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It isn't Electron's &lt;code&gt;powerMonitor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It isn't network monitoring.&lt;/p&gt;

&lt;p&gt;It's the &lt;strong&gt;combination&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A computer is already generating thousands of signals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Applications
Processes
CPU
Memory
Network
Power
Sleep
Wake
Idle
Lock
Unlock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Today, these signals are mostly presented independently.&lt;/p&gt;

&lt;p&gt;A desktop observability layer could connect them.&lt;/p&gt;

&lt;p&gt;And instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What's my CPU usage?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;we can finally ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What happened on my computer while I wasn't looking?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's a much more interesting monitoring problem.&lt;/p&gt;

</description>
      <category>electron</category>
      <category>desktopapps</category>
      <category>power</category>
      <category>tooling</category>
    </item>
    <item>
      <title>The Coverage Loop: Turning Free AI Tokens into Verified C++ Tests</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:11:55 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/the-coverage-loop-turning-free-ai-tokens-into-verified-c-tests-1jh5</link>
      <guid>https://dev.to/datacpp_3670/the-coverage-loop-turning-free-ai-tokens-into-verified-c-tests-1jh5</guid>
      <description>&lt;p&gt;Unit tests are boring. Coverage is not optional.&lt;br&gt;
I asked a free AI model to write my tests. It failed. Then I built a feedback loop.&lt;br&gt;
Here is the result: a reproducible pipeline that turns free tokens into measured coverage.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Generated Tests Miss Everything
&lt;/h2&gt;

&lt;p&gt;Models guess. They do not know your intent.&lt;br&gt;
A test that compiles is not a test that asserts. A test that asserts is not a test that covers.&lt;br&gt;
The fix is not a better prompt. The fix is a measurement loop.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Experiment
&lt;/h2&gt;

&lt;p&gt;MonkeyCode is an open-source AI coding tool. It offers free model access and a free server option.&lt;br&gt;
Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;br&gt;
I used its free tier for this experiment. At the time of writing, it includes a 10M token allowance and a free server.&lt;/p&gt;

&lt;p&gt;The target: a small C++ string utility.&lt;br&gt;
The goal: reach 90% line coverage with generated tests.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Loop
&lt;/h2&gt;

&lt;p&gt;Five steps. Each one is small.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send the header to the model. Ask for tests.&lt;/li&gt;
&lt;li&gt;Compile and run the tests.&lt;/li&gt;
&lt;li&gt;Run gcov. Get the coverage number.&lt;/li&gt;
&lt;li&gt;Feed the missing lines back to the model.&lt;/li&gt;
&lt;li&gt;Repeat until coverage plateaus.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the core script. It is simplified but runnable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;coverage_loop.py - generate C++ tests, measure coverage, iterate.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://your-provider/v1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;your-key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;free-model&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_tests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Write a C++ test file for this header:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="nf"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Current tests miss these lines: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hint&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="nf"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Add tests to cover them.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                         &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;choices&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_tests&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;g++&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-std=c++17&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--coverage&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-o&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tests&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;string_utils.cpp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test_string_utils.cpp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./tests&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gcov&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;string_utils.cpp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Lines executed&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;missing_lines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;12-15, 28-30&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;string_utils.h&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;hint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;lines &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;missing_lines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="n"&gt;test_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_tests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test_string_utils.cpp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;coverage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_tests&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CalledProcessError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;compilation failed, retrying&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;iteration &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;coverage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;coverage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set &lt;code&gt;BASE_URL&lt;/code&gt;, &lt;code&gt;API_KEY&lt;/code&gt;, and &lt;code&gt;MODEL&lt;/code&gt; to your provider's values. Drop your header and source in the same directory. Run it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python coverage_loop.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example Run
&lt;/h2&gt;

&lt;p&gt;One run produced this pattern. Your numbers will differ.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Iteration&lt;/th&gt;
&lt;th&gt;Coverage&lt;/th&gt;
&lt;th&gt;What changed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;42%&lt;/td&gt;
&lt;td&gt;Tests compiled, missed edge cases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;71%&lt;/td&gt;
&lt;td&gt;Added empty-string tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;88%&lt;/td&gt;
&lt;td&gt;Added null-byte handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;91%&lt;/td&gt;
&lt;td&gt;Plateau, stopped&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The loop works. The model found obvious edge cases. Empty strings. Negative numbers.&lt;br&gt;
It missed stateful behavior. Two calls in sequence. That is where gcov saved me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the Loop Breaks
&lt;/h2&gt;

&lt;p&gt;Free servers rate-limit. I added retry logic. It still stuttered.&lt;br&gt;
The model generated uncompilable tests. I skipped them. That wastes tokens.&lt;br&gt;
Coverage is not correctness. A test can cover a line and assert nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Should Skip This
&lt;/h2&gt;

&lt;p&gt;Safety-critical code. Do not trust generated tests.&lt;br&gt;
Legacy code with hidden dependencies. The model will guess wrong.&lt;br&gt;
Teams without a CI runner. The loop needs automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Free AI is not a test engineer. It is a test generator with a feedback loop.&lt;br&gt;
The loop turns tokens into coverage. Coverage tells you where to spend the next token.&lt;br&gt;
That is the real trick. Not more prompts. Better signals.&lt;br&gt;
Fork the script. Run it on your worst file. Tell me what breaks.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>testing</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
